package com.lvmama.rhino.common.utils

import java.io.File
import java.text.SimpleDateFormat
import java.util.{Calendar, Date, Locale}

import com.fasterxml.jackson.databind.JsonNode
import com.lvmama.rhino.common.entity._
import org.apache.commons.codec.binary.Base64
import org.apache.spark.sql.Row

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

/**
  * Created by yuanxiaofeng on 2016/6/1.
  */
object Utils {
  def initNginx(ngLog: String): NginxMan = {
    val startI = ngLog.indexOf("1.gif?") + 6
    val endI = ngLog.indexOf("HTTP/1.") - 1
    val log = ngLog.substring(startI, endI)
    NginxMan(NginxMan.unapply(log))
  }

  def initMsy(msyLog: String): MsyLog = {
    val startSeq: String = "/1.gif?"
    val startI = msyLog.indexOf(startSeq) + startSeq.length
    val endI = if (msyLog.indexOf("HTTP/1.") == -1) {
      (msyLog.indexOf("HTTP/2.") - 1)
    } else {
      (msyLog.indexOf("HTTP/1.") - 1)
    }
    if (endI != -2) {
      val log = msyLog.substring(startI, endI)
      MsyLog(MsyLog.unapply(log))
    } else {
      MsyLog(None)
    }
  }

  /**
    * 获取昨天的时间戳
    *
    * @return
    */
  def getYesterdayTimeInMillis(): Long = {
    val cal: Calendar = Calendar.getInstance()
    cal.add(Calendar.DATE, -1)
    cal.set(Calendar.HOUR, 0)
    cal.set(Calendar.HOUR_OF_DAY, 0)
    cal.set(Calendar.MINUTE, 0)
    cal.set(Calendar.SECOND, 0)
    cal.getTimeInMillis
  }

  def getLastHourDate(format: String = "yyyy/MM/dd/HH"): String = {
    val dateFormat: SimpleDateFormat = new SimpleDateFormat(format)
    val cal: Calendar = Calendar.getInstance()
    cal.add(Calendar.HOUR, -1)
    val yesterday = dateFormat.format(cal.getTime)
    yesterday
  }

  def getYesterday(format: String = "yyyy-MM-dd"): String = {
    val dateFormat: SimpleDateFormat = new SimpleDateFormat(format)
    val cal: Calendar = Calendar.getInstance()
    cal.add(Calendar.DATE, -1)
    val yesterday = dateFormat.format(cal.getTime)
    yesterday
  }

  def getToday(format: String = "yyyy-MM-dd"): String = {
    val dateFormat: SimpleDateFormat = new SimpleDateFormat(format)
    val cal: Calendar = Calendar.getInstance()
    val today = dateFormat.format(cal.getTime)
    today
  }

  def getTime(format: String = "yyyy-MM-dd:HH"): String = {
    val dateFormat: SimpleDateFormat = new SimpleDateFormat(format)
    val cal: Calendar = Calendar.getInstance()
    val time = dateFormat.format(cal.getTime)
    time
  }

  def getBetweenDate(start: Date, end: Date, format: String = "yyyy/MM/dd"): List[String] = {
    var begin = start
//    var result: List[String] = List()
    var result = ArrayBuffer[String]()

    var tempStart = Calendar.getInstance
    tempStart.setTime(begin)
    while ( {
      begin.getTime <= end.getTime
    }) {
      val sdf = new SimpleDateFormat(format)
      result :+ sdf.format(tempStart.getTime)
      result.append(sdf.format(tempStart.getTime))
      tempStart.add(Calendar.DAY_OF_YEAR, 1)
      begin = tempStart.getTime
    }
    result.toList
  }

  def timeFormat(time: Long, format: String = "yyyy-MM-dd:HH"): String = {
    val dateFormat: SimpleDateFormat = new SimpleDateFormat(format)
    dateFormat.format(time)
  }

  def date2Stamp(s: String, format: String = "yyyy-MM-dd HH:mm:ss"): Long = {
    val simpleDateFormat = new SimpleDateFormat(format)
    val date = simpleDateFormat.parse(s)
    date.getTime
  }

  def deleteAllFilesOfDir(path: File) {
    if (!path.exists())
      return
    if (path.isFile) {
      path.delete()
      return
    }
    val files = path.listFiles()
    for (file <- files) {
      deleteAllFilesOfDir(file)
    }
    path.delete()
  }

  val r = """data=[0-9A-Za-z+/%=]*""".r
  val r_782 = """(data=[0-9A-Za-z+/=]*)|(lvversion=\d\.\d\.\d)""".r

  def initWireless(log: String): WirelessClientMonitorLog = {
    /*
      val decodeLog = r.findFirstIn(log)
      if (decodeLog.isDefined) {
        val result = urlDecode(decodeLog.get, "UTF-8")
        val wireless = result.substring("data=".length)
        val wirelessLog = new String(Base64.decodeBase64(wireless), "UTF-8")
          .replace("\\n", "").replace("{", "").replace("}", "").replace("\"", "")
        WirelessClientMonitorLog(WirelessClientMonitorLog.unapply(wirelessLog))
      } else {
        new WirelessClientMonitorLog("", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
          Map.empty[String, String], "", "")
      }*/
    var ip = log.split(" - - ")(0)
    if (ip == Nil || ip == "") ip = "0.0.0.0"

    val strArr = log.split(" ")
    val url = if ((log.contains("http://") || log.contains("https://")) && strArr.length > 9) strArr(9) else ""

    val matchLog = r.findFirstIn(log)
    val data = if (matchLog.nonEmpty) matchLog.get else ""
    val decodeLog = urlDecode(urlDecode(data, "UTF-8"), "UTF-8")
    if (data.nonEmpty) {
      val wireless = decodeLog.substring("data=".length)
      val wirelessLog = new String(Base64.decodeBase64(wireless), "UTF-8")

      WirelessClientMonitorLog(WirelessClientMonitorLog.unapply(wirelessLog, ip, url))
    } else {
      new WirelessClientMonitorLog("", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
        Map.empty[String, String], 0L, "", "", "", "", "")
    }
  }

  val r_stat = """(data=[0-9A-Za-z+/%=]+)|(secondChannel=[A-Za-z]+)|(lvidfa=[A-Za-z0-9-]+)""".r

  def initStat(log: String): StatLogType = {
    val matchLog = r_stat.findAllMatchIn(log).toList
    val map = mutable.Map.empty[String, String]
    for (l <- matchLog) {
      val split = l.toString().split("=")
      map += (split(0) -> split(1))
    }
    if (map.get("data").nonEmpty) {
      val decodeLog = urlDecode(map.get("data").get, "UTF-8")
      val stat = new String(Base64.decodeBase64(decodeLog), "UTF-8")
      StatLogType(StatLogType.unapply(stat, map.getOrElse("secondChannel", ""), map.getOrElse("lvidfa", "")))
    } else {
      StatLogType()
    }
  }


  def urlDecode(s: String, enc: String): String = {
    var needToChange = false
    val numChars = s.length
    val sb = new StringBuilder(if (numChars > 500) numChars / 2 else numChars)
    var i = 0
    if (enc.length == 0)
      throw new UnsupportedOperationException("URLDecoder: empty string enc parameter")

    var c: Char = '\0'
    var bytes: Array[Byte] = null
    while (i < numChars) {
      c = s.charAt(i)
      c match {
        case '%' =>
          try {
            if (bytes == null)
              bytes = new Array[Byte]((numChars - i) / 3)
            var pos = 0

            while (((i + 2) < numChars) && (c == '%')) {
              val v = Integer.parseInt(s.substring(i + 1, i + 3), 16)
              if (v < 0)
                throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value")
              bytes(pos) = v.toByte
              pos = pos + 1
              i += 3
              if (i < numChars)
                c = s.charAt(i)
            }

            if ((i < numChars) && (c == '%'))
              throw new IllegalArgumentException(
                "URLDecoder: Incomplete trailing escape (%) pattern")
            sb.append(new String(bytes, 0, pos, enc))
          } catch {
            case e: NumberFormatException =>
              sb.append(c)
              i = i + 1
            //              throw new IllegalArgumentException(
            //                "URLDecoder: Illegal hex characters in escape (%) pattern - "
            //                  + e.getMessage)
          }
          needToChange = true
        case _ =>
          sb.append(c)
          i = i + 1
      }
    }
    if (needToChange) sb.toString else s
  }

  //过滤掉emoji表情
  val emojiFilter: String => String = str => {
    if (str != null && !str.isEmpty && !" ".equals(str)) {
      val sb: StringBuilder = new StringBuilder
      for (i <- 0 until str.length) {
        val ch: Char = str.charAt(i)
        if (isNotEmojiCharacter(ch)) {
          sb.append(ch)
        }
      }
      sb.toString()
    } else {
      str
    }
  }

  lazy val isNotEmojiCharacter: Char => Boolean = ch =>
    ((ch == 0x0) || (ch == 0x9) || (ch == 0xA) || (ch == 0xD)
      || ((ch >= 0x20) && (ch <= 0xD7FF)) || ((ch >= 0xE000) && (ch <= 0xFFFD))
      || ((ch >= 0x10000) && (ch <= 0x10FFFF)))


  /**
    * H5页面访问时长监控将日志文件转换成HDFS代码
    *
    * @param log
    * @return
    */
  def initPageMonitor(log: String): H5PageMonitorLog = {
    val createDate = getDate(log)
    val decodeLog = r.findFirstIn(log)
    if (decodeLog.isDefined) {
      val result = urlDecode(decodeLog.get, "UTF-8")
      val pageMonitor = result.substring("data=".length)
      val pageMonitorLog = new String(Base64.decodeBase64(pageMonitor), "UTF-8")
        .replace("\\n", "")
      H5PageMonitorLog(H5PageMonitorLog.unapply(pageMonitorLog, createDate))
    }
    else {
      new H5PageMonitorLog("", "", "", "", "", "", "", "", "")
    }
  }

  /**
    * 获取nginx日志中的服务器时间
    * 日志格式例如：10.113.1.214 - - [2016-12-07T17:56:19+08:00] "GET /stat/1.gif?data=eyJvdCI6IkNNIiwibnQiOiJ3aWZpIiwicHJvdiI6Iuaxn+iLjyIsImNpdHkiOiLljZfkuqwiOiJjaSIsIjEiLCJsdCIsIjMuMDEyIiwiaXNsdiI6IjEifQ== HTTP/1.1" 200 43 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36" "-" 0.000 -
    * 获取的时间为 2016-12-07T17:56:19+08:00 转换成mysql需要的时间为2016-12-07 17:56:19
    *
    * @param log
    * @return
    */
  def getDate(log: String): String = {
    val nginxTime = log.substring(log.indexOf("[") + 1, log.indexOf("]"))
    //日志创建时间
    val createDate = nginxTime.substring(0, nginxTime.indexOf("+")).replace("T", " ")
    createDate
  }

  def extractFieldNames[T <: Product : Manifest] = {
    implicitly[Manifest[T]].erasure.getDeclaredFields.map(_.getName)
  }

  def getDiffYears(first: Date, last: Date): Int = {
    val a = getCalendar(first)
    val b = getCalendar(last)
    var diff = b.get(Calendar.YEAR) - a.get(Calendar.YEAR)
    if (a.get(Calendar.MONTH) > b.get(Calendar.MONTH) ||
      (a.get(Calendar.MONTH) == b.get(Calendar.MONTH) && a.get(Calendar.DATE) > b.get(Calendar.DATE))) {
      diff -= 1
    }
    diff
  }

  def getCalendar(date: Date): Calendar = {
    val cal = Calendar.getInstance(Locale.CHINA)
    cal.setTime(date)
    cal
  }

  def isEntirelyInBasicMultilingualPlane(text: String): Boolean = {
    for (i <- 0 until text.length) {
      if (Character.isSurrogate(text.charAt(i))) {
        return false
      }
    }
    true
  }

  /**
    * 性能监控二期页面监控将日志文件转换成HDFS代码
    *
    * @param log
    * @return
    */
  def initMonitorPage(log: String): MonitorPageLog = {
    val createDate = getDate(log)
    val decodeLog = r.findFirstIn(log)
    if (decodeLog.isDefined) {
      val result = urlDecode(decodeLog.get, "UTF-8")
      val pageMonitor = result.substring("data=".length)
      val pageMonitorLog = new String(Base64.decodeBase64(pageMonitor), "UTF-8")
        .replace("\\n", "")
      MonitorPageLog(MonitorPageLog.unapply(pageMonitorLog, createDate))
    }
    else {
      new MonitorPageLog("", "", "", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, "")
    }
  }

  /**
    * 鹰眼系统二期页面监控将日志文件转换成HDFS代码
    *
    * @param log
    * @return
    */
  def initMonitorPageInfo(log: String, threshold: Map[Any, Row]): MonitorPageInfoLog = {
    try {
      val createDate = getDate(log)
      val decodeLog = r.findFirstIn(log)
      if (decodeLog.isDefined) {
        val result = urlDecode(decodeLog.get, "UTF-8")
        val pageMonitor = result.substring("data=".length)
        val pageMonitorLog = new String(Base64.decodeBase64(pageMonitor), "UTF-8")
          .replace("\\n", "")
        MonitorPageInfoLog.process(pageMonitorLog, createDate, threshold)
      }
      else {
        new MonitorPageInfoLog("", "", "", 0l, null, null, null, null, null)
      }
    }
    catch {
      case e: Exception =>
        new MonitorPageInfoLog("", "", "", 0l, null, null, null, null, null)
    }
  }

  def initRequestFlow(log: String): (String, String, String, Long, Array[JsonNode]) = {
    val emptyArray = new Array[JsonNode](0)
    try {
      val createDate = getDate(log)
      val decodeLog = r.findFirstIn(log)
      if (decodeLog.isDefined) {
        val result = urlDecode(decodeLog.get, "UTF-8")
        val pageMonitor = result.substring("data=".length)
        val pageMonitorLog = new String(Base64.decodeBase64(pageMonitor), "UTF-8")
          .replace("\\n", "")
        RequestFlow.preRequestFlow(pageMonitorLog, createDate)
      }
      else {
        return ("", "", "", 0l, emptyArray)
      }
    }
    catch {
      case e: Exception =>
        ("", "", "", 0l, emptyArray)
    }
  }

  def initJsError(log: String): (String, String, Array[JsonNode]) = {
    val emptyArray = new Array[JsonNode](0)
    try {
      val decodeLog = r.findFirstIn(log)
      if (decodeLog.isDefined) {
        val result = urlDecode(decodeLog.get, "UTF-8")
        val jsError = result.substring("data=".length)
        val jsErrorLog = new String(Base64.decodeBase64(jsError), "UTF-8")
          .replace("\\n", "")
        JsError.preJsError(jsErrorLog)
      }
      else {
        return ("", "", emptyArray)
      }
    }
    catch {
      case e: Exception =>
        ("", "", emptyArray)
    }
  }

  def main(args: Array[String]): Unit = {
    //val log = "10.115.1.166 - - [2017-12-22T16:44:43+08:00] \"GET /monitorPage/1.gif?data=eyJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjU1MDAvc3RhdGljX3Byb2plY3QvbGliL3NyYy9sb3NjL3Rlc3QuaHRtbCIsInBpZCI6InRWUlNiSnpsQnpCZzlrbW8iLCJ0ZWMiOiJXQVAiLCJlcyI6eyJyZXFzIjoiMTUxMzkzMjc2MjI3NSIsInJlcGUiOiIxNTEzOTMyNzYyMjgwIiwicmVwcyI6IjE1MTM5MzI3NjIyNzciLCJkbGUiOiIxNTEzOTMyNzYyMjczIiwiZGxzIjoiMTUxMzkzMjc2MjI3MyIsImNzIjoiMTUxMzkzMjc2MjI3MyIsImNlIjoiMTUxMzkzMjc2MjI3MyIsInNzIjowLCJsZSI6IjE1MTM5MzI3NjI1NjYiLCJucyI6IjE1MTM5MzI3NjIyNzIiLCJ1bCI6IjE1MTM5MzI3NjIyODAiLCJycyI6MCwicmUiOjAsImRsIjoiMTUxMzkzMjc2MjI4OCIsImxlcyI6IjE1MTM5MzI3NjI1NjYifSwicnMiOlt7Im5hIjoiaHR0cDovLzEyNy4wLjAuMTo1NTAwL3N0YXRpY19wcm9qZWN0L2xpYi9zcmMvbG9zYy90ZXN0Lmh0bWwiLCJ0cCI6Im5hdmlnYXRpb24iLCJkdXIiOjI5NC40NywiZGJzIjoyOTk1LCJzdCI6MCwicnQiOjcuODUwMDAwMDAwMDAwMDAxfSx7Im5hIjoiaHR0cDovLzEyNy4wLjAuMTo1NTAwL3N0YXRpY19wcm9qZWN0L2xpYi9wbHVnaW5zL3B1YmxpYy8xLjAvcHVibGljLTEuNS5taW4uanMiLCJ0cCI6InNjcmlwdCIsImR1ciI6MTU2LjUzMDAwMDAwMDAwMDAzLCJkYnMiOjg1NzEsInN0IjoxNy41MywicnQiOjE3NC4wNjAwMDAwMDAwMDAwM30seyJuYSI6Imh0dHA6Ly9waWMubHZtYW1hLmNvbS9tb2JpbGUvbGliL3BsdWdpbnMvbmF0aXZlVXRpbC8xLjAvbmF0aXZlVXRpbC0xLjkuMy5taW4uanMiLCJ0cCI6InNjcmlwdCIsImR1ciI6MTYwLjcyNSwiZGJzIjoiTk9ORSIsInN0IjoxNy43NDAwMDAwMDAwMDAwMDIsInJ0IjoxNzguNDY1fSx7Im5hIjoiaHR0cDovL3BpYy5sdm1hbWEuY29tL21vYmlsZS9wbHVnaW5zL25hdGl2ZUpzL2dlb2xvY2F0aW9uL2Rlc3QvZ2VvbG9jYXRpb24ubWluLmpzIiwidHAiOiJzY3JpcHQiLCJkdXIiOjE2MC4yNjAwMDAwMDAwMDAwMiwiZGJzIjoiTk9ORSIsInN0IjoxNy44NywicnQiOjE3OC4xMzAwMDAwMDAwMDAwMn0seyJuYSI6Imh0dHA6Ly8xMjcuMC4wLjE6NTUwMC9zdGF0aWNfcHJvamVjdC9saWIvc3JjL2xvc2MvZGVzdC9sb3NjLmpzIiwidHAiOiJzY3JpcHQiLCJkdXIiOjE1OS41MTUwMDAwMDAwMDAwMSwiZGJzIjoyMzk2NCwic3QiOjE4LjAzNTAwMDAwMDAwMDAwNCwicnQiOjE3Ny41NX0seyJuYSI6ImZpcnN0LXBhaW50IiwidHAiOiJvdGhlciIsImR1ciI6MCwiZGJzIjoiTk9ORSIsInN0IjoyNTMuNjEsInJ0IjoiTk9ORSJ9LHsibmEiOiJmaXJzdC1jb250ZW50ZnVsLXBhaW50IiwidHAiOiJvdGhlciIsImR1ciI6MCwiZGJzIjoiTk9ORSIsInN0IjoyNTMuNjE1MDAwMDAwMDAwMDQsInJ0IjoiTk9ORSJ9XSwiZGkiOnsicmVzbCI6Ik5PTkUiLCJkbSI6Ik5PTkUiLCJkdCI6Ik5PTkUiLCJvcyI6Ik5PTkUiLCJ1YSI6Ik1vemlsbGEvNS4wIChpUGhvbmU7IENQVSBpUGhvbmUgT1MgOV8xIGxpa2UgTWFjIE9TIFgpIEFwcGxlV2ViS2l0LzYwMS4xLjQ2IChLSFRNTCwgbGlrZSBHZWNrbykgVmVyc2lvbi85LjAgTW9iaWxlLzEzQjE0MyBTYWZhcmkvNjAxLjEifSwidWkiOnsiaXAiOiJOT05FIiwib3QiOiJOT05FIiwibnQiOiJOT05FIiwiY3QiOiJOT05FIiwicHJvdiI6Ik5PTkUiLCJsYSI6IiIsImxvIjoiIiwibW4iOiJOT05FIiwidWkiOiJOT05FIn0sInV0Ijp7IndzIjoiMjUzLjYxNTAwMDAwMDAwMDA0IiwiZnMiOiIyOTQiLCJpdCI6IjI5NCIsImNvbXAiOiJOT05FIn0sInBmIjoiV0FQIn0= HTTP/1.1\" 200 43 \"-\" \"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36\" \"-\" 0.000 -"
    //val pageMonitorLog = initMonitorPageInfo(log)
    val log = "10.115.1.166 - - [2017-12-28T15:11:09+08:00] \"GET /monitorPageJs/1.gif?data=eyJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjU1MDAvc3RhdGljX3Byb2plY3QvbGliL3NyYy9sb3NjL3Rlc3QuaHRtbCIsInBpZCI6IkRXUjRWdU5qMVd5NVo1c2EiLCJkYXRhIjpbeyJldCI6IlJlZmVyZW5jZUVycm9yIiwibXNnIjoiIGFiYyBpcyBub3QgZGVmaW5lZCIsInN0ayI6ImF0IGh0dHA6Ly8xMjcuMC4wLjE6NTUwMC9zdGF0aWNfcHJvamVjdC9saWIvc3JjL2xvc2MvdGVzdC5odG1sOjQ1OjEzIiwiam4iOiJodHRwOi8vMTI3LjAuMC4xOjU1MDAvc3RhdGljX3Byb2plY3QvbGliL3NyYy9sb3NjL3Rlc3QuaHRtbCJ9XX0= HTTP/1.1\" 200 43 \"-\" \"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36\" \"-\" 0.000 -"
    val ss = initRequestFlow(log)
    System.out.print("fsdf")
  }
}

